package com.wzy.facetextview.widget;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.text.Editable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Xml;
import android.view.KeyEvent;
import android.widget.EditText;

import com.wzy.facetextview.Utils.AppUtils;
import com.wzy.facetextview.Utils.CacheSp;
import com.wzy.facetextview.Utils.ConstantsUtil;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * 表情管理
 */
public class FaceManager {
    
    private static final String TAG = "wang.FaceManager";
    
    private static final String DEFAULT_FACE_INSTALLED_DIR = "faces";
    private static final String FACE_INSTALLED_CONFIG_FILE = "face.xml";
    private static final String FACE_DEFAULT_DIR = "faces";
    
    private static final int DEFAULT_FACE_PKG_CURRENT_VERSION = 17;
    
    private static final int FACE_CONTENT_LENGTH_MIN = 2;
    private static final int WIDTH_PIX_1440 = 1440;
    private static final int WIDTH_PIX_1080 = 1080;
    private static final int WIDTH_PIX_720 = 720;
    private static final int WIDTH_PIX_540 = 540;
    private static final int WIDTH_PIX_480 = 480;
    
    private static int mFaceCodeMaxLength = 10;
    
    // xml tag
    private static final String FACE_ROOT = "faces";
    private static final String FACE_TAG = "face";
    
    private static final String FACE_PKG_FORMAT = ".vgz";
    
    private static final String FACE_MATCHER_REGULAR = "(\\[[^\\[\\s]+?:[^\\s^\\[]+?:\\d+\\])";
    
    private static final int FACE_CODES_LOWER_LIMIT = 3;
    
    private static Pattern mFacePattern;
    
    static {
        mFacePattern = Pattern.compile(FaceManager.FACE_MATCHER_REGULAR);
    }
    
    private static FaceManager sFaceManager;
    
    private static final byte[] sLock = new byte[0];
    
    private Context mContext;
    private HashMap<String, FacePackage> mFacePackages = new HashMap<String, FacePackage>();
    private ArrayList<FacePackage> mOrderedFacePkgs = new ArrayList<FacePackage>();
    private ArrayList<OnFacePackagesChangededCallback> mCallbacks;

    public static FaceManager getInstance(Context context) {

        synchronized (sLock) {
            if (sFaceManager == null) {
                sFaceManager = new FaceManager(context);
            }
            return sFaceManager;
        }
    }

    private FaceManager(Context context) {
        mContext = context;
        loadFacePackages();
    }

    public void release() {

        sFaceManager = null;
    }

    // install 3part face package
    public void install3PartFacePackage(String path) {

        File file = new File(path);
        if (file != null && file.exists()) {
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(file);
                installFacePackage(fis);
                loadFacePackages();
            } catch (FileNotFoundException e) {
            } finally {
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                    }
                }
            }
        }
    }

    /**
     * 检测默认版本表情包，如果DEFAULT_FACE_PKG_CURRENT_VERSION发生改变，则升级默认版本包 主要用在应用的版本升级
     */
    private void checkDefaultFacePkgVersion() {

        CacheSp prefs = CacheSp.getInstance(mContext);
        int oldVersion = prefs.getInt(ConstantsUtil.PREF_FACE_PKGS_DEFAUL_VERSION, -1);

        Log.d(TAG, "oldVersion = " + oldVersion + ", currentVersion = " + DEFAULT_FACE_PKG_CURRENT_VERSION);

        if (DEFAULT_FACE_PKG_CURRENT_VERSION > oldVersion && oldVersion != -1) {
            updateDefaultFacePackage();
            prefs.putInt(ConstantsUtil.PREF_FACE_PKGS_DEFAUL_VERSION, DEFAULT_FACE_PKG_CURRENT_VERSION);
        } else {
            prefs.putInt(ConstantsUtil.PREF_FACE_PKGS_DEFAUL_VERSION, DEFAULT_FACE_PKG_CURRENT_VERSION);
            Collections.sort(mOrderedFacePkgs, mPackageComparator);
        }
    }

    private final Comparator<FacePackage> mPackageComparator = new Comparator<FacePackage>() {
        @Override
        public int compare(FacePackage lhs, FacePackage rhs) {

            return lhs.getKey().compareToIgnoreCase(rhs.getKey());
        }

    };

    private void updateDefaultFacePackage() {

        uninstallDefaultFacePackages();
        installDefaultFacePackages();
    }

    /**
     * 安装表情包
     *
     * @param is
     */
    private void installFacePackage(InputStream is) {

        extractFacePackage(is);
    }

    /**
     * 卸载表情包
     *
     * @param key
     */
    public void unInstallPackage(String key) {

        Log.d(TAG, "face package removed, key = " + key);
        FacePackage facePackage = mFacePackages.get(key);
        String dir = facePackage.mDir;
        if (TextUtils.isEmpty(dir)) {
            return;
        }

        unInstallPackageImpl(dir);

        if (mCallbacks != null) {
            for (OnFacePackagesChangededCallback callback : mCallbacks) {
                callback.onFacePackageRemoved(facePackage);
            }
        }

        mFacePackages.remove(key);
        mOrderedFacePkgs.remove(facePackage);
    }

    private void uninstallDefaultFacePackages() {

        Log.d(TAG, "uninstallDefaultFacePackages");
        ArrayList<FacePackage> orderedFacePkgs = new ArrayList<FacePackage>(mOrderedFacePkgs);
        for (FacePackage facePackage : orderedFacePkgs) {
            if (!facePackage.mDefaultPkg) {
                continue;
            }
            unInstallPackage(facePackage.mKey);
        }
    }

    private void unInstallPackageImpl(String path) {

        Log.d(TAG, "unInstallPackageImpl, path = " + path);
        File file = new File(path);
        deleteDirectory(file);
    }

    /**
     * 递归删除文件及文件夹
     *
     * @param dir
     */
    private void deleteDirectory(File dir) {

        if (dir.isDirectory()) {

            String[] children = dir.list();

            if (children != null && children.length > 0) {
                for (String child : children) {
                    deleteDirectory(new File(dir, child));
                }
            }
        }

        dir.delete();
    }

    /**
     * 注册表情包发生改变回调
     *
     * @param callback
     */
    public void registerOnFacePackagesChangedCallback(OnFacePackagesChangededCallback callback) {

        if (callback == null) {
            return;
        }
        if (mCallbacks == null) {
            mCallbacks = new ArrayList<OnFacePackagesChangededCallback>();
        }
        mCallbacks.add(callback);
    }

    /**
     * 解注册
     *
     * @param callback
     */
    public void unregisterOnFacePackagesChangedCallback(OnFacePackagesChangededCallback callback) {

        if (callback == null || mCallbacks == null) {
            return;
        }
        mCallbacks.remove(callback);
    }

    /**
     * 根据key值找到表情包
     *
     * @param key
     * @return
     */
    public FacePackage getFacePackage(String key) {

        if (TextUtils.isEmpty(key)) {
            return null;
        }
        return mFacePackages.get(key);
    }

    /**
     * 获取表情包
     *
     * @return
     */
    public ArrayList<FacePackage> getFacePackages() {

        return mOrderedFacePkgs;
    }

    public static Drawable getFace(Context context, String source) {

        Drawable drawable = null;

        String[] content = source.split("/");
        int len = content.length;
        if (len > FACE_CONTENT_LENGTH_MIN) {
            String faceKey = content[len - 2];
            String faceCode = content[len - 1];

            if (TextUtils.isEmpty(faceKey) || TextUtils.isEmpty(faceCode)) {
                return drawable;
            }

            String[] codeSplit = faceCode.split("\\.");
            faceCode = codeSplit[0];

            FacePackage facePackage = FaceManager.getInstance(context).getFacePackage(faceKey);
            if (facePackage == null) {
                return drawable;
            }

            Face face = facePackage.getFace(faceCode);
            if (face == null) {
                return drawable;
            }

            try {
                drawable = new BitmapDrawable(face.getPreview());
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (drawable != null) {

                DisplayMetrics dm = new DisplayMetrics();
                ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
                int drawablebounds = 20;
                if (dm.widthPixels == WIDTH_PIX_1080) {
                    drawablebounds = 80;
                } else if (dm.widthPixels == WIDTH_PIX_720) {
                    drawablebounds = 70;
                } else if (dm.widthPixels == WIDTH_PIX_540) {
                    drawablebounds = 40;
                } else if (dm.widthPixels == WIDTH_PIX_1440) {
                    drawablebounds = 100;
                } else if (dm.widthPixels == WIDTH_PIX_480) {
                    drawablebounds = 40;
                } else {
                    drawablebounds = 50;
                }

                drawable.setBounds(0, 0, drawablebounds, drawablebounds);
            }
        }

        return drawable;
    }

    public static Drawable getCompatFace(Context context, String source) {

        Drawable drawable = null;

        final String IMAGE_REGEX = "\\d{1,3}.gif";

        Matcher matcher = Pattern.compile(IMAGE_REGEX, Pattern.CASE_INSENSITIVE).matcher(source);

        if (matcher.find()) {

            String face = matcher.group();
            face = face.replace("gif", "png");
            InputStream is = null;

            try {

                is = context.getAssets().open("compat_face/" + face);
                Bitmap bm = BitmapFactory.decodeStream(is);
                drawable = new BitmapDrawable(bm);
                DisplayMetrics dm = new DisplayMetrics();
                ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);

                int drawablebounds = 20;
                if (dm.widthPixels == WIDTH_PIX_1080) {
                    drawablebounds = 80;
                } else if (dm.widthPixels == WIDTH_PIX_720) {
                    drawablebounds = 70;
                } else if (dm.widthPixels == WIDTH_PIX_540) {
                    drawablebounds = 40;
                } else if (dm.widthPixels == WIDTH_PIX_1440) {
                    drawablebounds = 100;
                } else if (dm.widthPixels == WIDTH_PIX_480) {
                    drawablebounds = 40;
                } else {
                    drawablebounds = 50;
                }

                drawable.setBounds(0, 0, drawablebounds, drawablebounds);

            } catch (IOException e) {
                e.printStackTrace();
            } finally {

                try {
                    if (is != null) {
                        is.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return drawable;
    }

    public interface OnFacePackagesChangededCallback {
        public void onFacePackageLoaded(FacePackage facePackage);

        public void onFacePackageRemoved(FacePackage facePackage);
    }

    public static String makeFaceCode(FacePackage pkg, Face face) {

        return "[" + pkg.getKey() + ":" + face.getCode() + ":" + pkg.getVersion() + "]";
    }

    public static int getFaceCodeMaxLen(FacePackage pkg) {

        // [key:code:version]
        return pkg.getKey().length() + pkg.getCodeMaxLen() + String.valueOf(pkg.getVersion()).length() + 4;
    }

    public static int getFaceCodeMaxLen() {

        return mFaceCodeMaxLength;
    }

    public static int getFaceCodeMinLen() {

        return 7;// [0:1:2]
    }

    public static Pattern getFacePattern() {

        return mFacePattern;
    }

    public static void onFaceSelected(EditText editText, String faceCode) {

        if (editText == null) {
            return;
        }

        int index = editText.getSelectionStart();
        Editable editable = editText.getText();

        if (editable == null) {
            return;
        }

        editable.insert(index, faceCode);
    }

    public static void onDeleteFaceSelected(EditText editText, FacePackage facePackage) {

        final KeyEvent keyEventDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
        editText.onKeyDown(KeyEvent.KEYCODE_DEL, keyEventDown);
    }

    public static boolean isFaceEndChar(char c) {

        return c == ']';
    }

    public static boolean isFaceStartChar(char c) {

        return c == '[';
    }

    public static class FacePackage {
        private String mKey;
        private int mVersion;
        private Drawable mIcon;
        private String mText;
        private String mDesc;
        private float mWidth;
        private float mHeight;
        private boolean mBig;

        private int mCodeMaxLen;
        private String mDir;
        private boolean mDefaultPkg;

        private HashMap<String, Face> mFaces = new HashMap<String, Face>();
        private ArrayList<Face> mOrderedFaces = new ArrayList<Face>();

        public String getKey() {

            return mKey;
        }

        public int getVersion() {

            return mVersion;
        }

        public Drawable getIcon() {

            return mIcon;
        }

        public String getText() {

            return mText;
        }

        public String getDesc() {

            return mDesc;
        }

        public float getWidth() {

            return mWidth;
        }

        public float getHeight() {

            return mHeight;
        }

        public boolean isBig() {

            return mBig;
        }

        public int getCodeMaxLen() {

            return mCodeMaxLen;
        }

        public Face getFace(String code) {

            return mFaces.get(code);
        }

        public ArrayList<Face> getFaces() {

            return mOrderedFaces;
        }

    }

    public static class Face {
        private String mCode;
        private String mFacePath;
        private String mText;
        private Bitmap mPreview;
        private int mOrder;
        private String mAbsolutelyPath;

        public String getCode() {

            return mCode;
        }

        public String getFacePath() {

            return mFacePath;
        }

        public String getText() {

            return mText;
        }

        public Bitmap getPreview() {

            return mPreview;
        }

        public String getAbsolutelyPath() {

            return mAbsolutelyPath;
        }

    }

    /**
     * 安装默认表情包
     */
    private void installDefaultFacePackages() {

        Log.d(TAG, "installDefaultFacePackages");

        try {
            String[] fileNames = mContext.getAssets().list(FACE_DEFAULT_DIR);

            for (String fileName : fileNames) {

                if (TextUtils.isEmpty(fileName)) {
                    continue;
                }

                Log.d(TAG, "installDefaultFacePackages, fileName = " + fileName);
                if (fileName.endsWith(FACE_PKG_FORMAT)) {
                    InputStream is = mContext.getAssets().open(FACE_DEFAULT_DIR + File.separator + fileName);
                    installFacePackage(is);
                }
            }
            loadFacePackages();
        } catch (IOException e) {
            Log.i(TAG, "installDefaultFacePackages ", e);
        }
    }

    /**
     * 从data空间加载表情包
     */
    private void loadFacePackages() {

        FaceParserTask task = new FaceParserTask();
        task.executeOnExecutor(ConstantsUtil.THREAD_POOL_EXECUTOR, (Void) null);
    }

    public String getFacePackageInstallDir() {

        return mContext.getFilesDir() + File.separator + DEFAULT_FACE_INSTALLED_DIR;
    }

    /**
     * 解压表情包到data空间
     *
     * @param is
     */
    private void extractFacePackage(InputStream is) {

        String targetDir = getFacePackageInstallDir();
        final int BUFFER = 4096;
        ZipInputStream zis = null;
        try {
            BufferedOutputStream dest = null;
            FileOutputStream fos = null;
            zis = new ZipInputStream(is);
            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {
                try {
                    String entryName = entry.getName();
                    File targetFile = new File(targetDir);
                    if (!targetFile.exists()) {
                        targetFile.mkdirs();
                    }

                    if (entry.isDirectory()) {
                        File entryFile = new File(targetDir + File.separator + entryName);
                        if (!entryFile.exists()) {
                            entryFile.mkdirs();
                        }
                        continue;
                    }

                    File entryFile = new File(targetDir + File.separator + entryName);
                    byte[] data = new byte[BUFFER];
                    fos = new FileOutputStream(entryFile);
                    dest = new BufferedOutputStream(fos, BUFFER);
                    int count;
                    while ((count = zis.read(data, 0, BUFFER)) != -1) {
                        dest.write(data, 0, count);
                    }
                    dest.flush();
                } catch (Exception e) {
                    Log.i(TAG, "extractFace exception: ", e);
                } finally {
                    if (dest != null) {
                        dest.close();
                    }
                    if (fos != null) {
                        fos.close();
                    }
                }
            }
        } catch (Exception e) {
            Log.i(TAG, "extractFace exception2: ", e);
        } finally {
            if (zis != null) {
                try {
                    zis.close();
                } catch (IOException e) {
                }
            }
        }
    }

    private class FaceParserTask extends AsyncTask<Void, Void, Void> {

        private ArrayList<FacePackage> mFacePkgs;

        private FaceParserTask() {
        }

        @Override
        protected Void doInBackground(Void... params) {

            String facePkgsDir = getFacePackageInstallDir();
            if (TextUtils.isEmpty(facePkgsDir)) {
                return null;
            }

            File facePkgsFile = new File(facePkgsDir);
            if (!facePkgsFile.exists() || !facePkgsFile.isDirectory()) {
                return null;
            }

            File[] facePkgFiles = facePkgsFile.listFiles();
            if (facePkgFiles == null || facePkgFiles.length == 0) {
                return null;
            }

            for (File file : facePkgFiles) {

                if (file == null || file.isFile()) {
                    continue;
                }

                FacePackage facePackage = parserFacePackage(file);
                if (facePackage != null) {
                    if (mFacePkgs == null) {
                        mFacePkgs = new ArrayList<FacePackage>();
                    }
                    mFacePkgs.add(facePackage);
                }
            }

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {

            super.onPostExecute(result);

            // 默认表情包是否已加载
            boolean defaultPkgLoaded = false;

            if (mFacePkgs != null) {

                for (FacePackage fp : mFacePkgs) {

                    String key = fp.getKey();

                    if (TextUtils.isEmpty(key)) {
                        continue;
                    }

                    if (fp.mDefaultPkg) {
                        defaultPkgLoaded = true;
                    }

                    if (mFacePackages.containsKey(key)) {
                        continue;
                    }

                    mFacePackages.put(key, fp);

                    mOrderedFacePkgs.add(fp);

                    int faceCodeLen = getFaceCodeMaxLen(fp);

                    if (faceCodeLen > mFaceCodeMaxLength) {
                        mFaceCodeMaxLength = faceCodeLen;
                    }

                    Log.d(TAG, "FaceParserTask, face package loaded, key = " + key + ", mFaceCodeMaxLength = "
                            + mFaceCodeMaxLength);

                    if (mCallbacks != null) {
                        for (OnFacePackagesChangededCallback callback : mCallbacks) {
                            callback.onFacePackageLoaded(fp);
                        }
                    }
                }
            }

            Log.d(TAG, "FaceParserTask, defaultPkgLoaded = " + defaultPkgLoaded);

            /**
             * 如果默认表情包已经加载，则， 否则安装默认表情包
             */
            if (defaultPkgLoaded) {
                checkDefaultFacePkgVersion();
            } else {
                installDefaultFacePackages();
            }
        }

        private FacePackage parserFacePackage(File dirFile) {

            String dirPath = dirFile.getAbsolutePath();
            String faceConfigFilePath = dirPath + File.separator + FACE_INSTALLED_CONFIG_FILE;
            File faceConfigFile = new File(faceConfigFilePath);
            if (faceConfigFile == null || faceConfigFile.isDirectory()) {
                return null;
            }
            return parserFacePackageXml(dirPath, faceConfigFile);
        }

        private FacePackage parserFacePackageXml(String dirPath, File xmlFile) {

            FacePackage result = null;
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(xmlFile);

                XmlPullParser parser = Xml.newPullParser();
                parser.setInput(fis, "UTF-8");

                beginDocument(parser, FACE_ROOT);
                result = new FacePackage();

                String name = parser.getName();
                if (FACE_ROOT.equals(name)) {
                    result.mDir = dirPath;
                    result.mKey = getAttributeValue(parser, 0);

                    String version = getAttributeValue(parser, 1);
                    result.mVersion = TextUtils.isEmpty(version) ? 0 : Integer.parseInt(version);

                    String iconName = getAttributeValue(parser, 2);
                    result.mIcon = Drawable.createFromPath(dirPath + File.separator + iconName);

                    result.mText = getAttributeValue(parser, 3);
                    result.mDesc = getAttributeValue(parser, 4);

                    String width = getAttributeValue(parser, 5);
                    String height = getAttributeValue(parser, 6);
                    result.mWidth = TextUtils.isEmpty(width) ? 0
                            : Float.valueOf(width) * AppUtils.getInstance(mContext).getScreenDensity();
                    result.mHeight = TextUtils.isEmpty(height) ? 0
                            : Float.valueOf(height) * AppUtils.getInstance(mContext).getScreenDensity();

                    String big = getAttributeValue(parser, 7);
                    if (!TextUtils.isEmpty(big)) {
                        result.mBig = Integer.parseInt(big) == 1;
                    }

                    String defaultPkg = getAttributeValue(parser, 8);
                    result.mDefaultPkg = TextUtils.isEmpty(defaultPkg) ? false : Integer.parseInt(defaultPkg) == 1;
                }

                final int depth = parser.getDepth();
                int type;
                int codeMaxLen = 0;
                while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
                        && type != XmlPullParser.END_DOCUMENT) {

                    if (type != XmlPullParser.START_TAG) {
                        continue;
                    }

                    name = parser.getName();
                    if (FACE_TAG.equals(name)) {
                        String code = getAttributeValue(parser, 0);
                        String previewPath = getAttributeValue(parser, 1);
                        String facePath = getAttributeValue(parser, 2);
                        String text = getAttributeValue(parser, 3);
                        String order = getAttributeValue(parser, 4);

                        if (TextUtils.isEmpty(code) || result.mFaces.containsKey(code)) {
                            continue;
                        }

                        if (TextUtils.isEmpty(facePath)) {
                            continue;
                        }
                        if (TextUtils.isEmpty(previewPath)) {
                            previewPath = facePath;
                        }

                        File previewFile = new File(dirPath + File.separator + previewPath);
                        BitmapFactory.Options options = new BitmapFactory.Options();
                        options.inPreferredConfig = Bitmap.Config.ARGB_8888;

                        FileInputStream is = null;
                        Bitmap bitmap = null;

                        try {

                            is = new FileInputStream(previewFile);
                            bitmap = BitmapFactory.decodeStream(is, null, options);

                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {

                            if (is != null) {
                                try {
                                    is.close();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }

                        if (is == null || bitmap == null) {
                            Log.e(TAG, "something is error ,FileInputStream is null");
                            continue;
                        }

                        Bitmap previewBitmap = bitmap;

                        if (result.mWidth > 0 && result.mHeight > 0) {
                            previewBitmap = Bitmap.createScaledBitmap(bitmap, (int) result.mWidth, (int) result.mHeight,
                                    true);
                        }

                        if (previewBitmap != null) {
                            result.mWidth = previewBitmap.getWidth();
                            result.mHeight = previewBitmap.getHeight();
                            Face face = new Face();
                            face.mCode = code;
                            face.mFacePath = facePath;
                            face.mText = text;
                            face.mPreview = previewBitmap;
                            face.mOrder = TextUtils.isEmpty(order) ? 0 : Integer.parseInt(order);
                            face.mAbsolutelyPath = dirPath + File.separator + facePath;
                            result.mFaces.put(code, face);
                            result.mOrderedFaces.add(face);

                            int len = code.length();
                            if (len > codeMaxLen) {
                                codeMaxLen = len;
                            }
                        }
                    }
                }
                result.mCodeMaxLen = codeMaxLen;
                Collections.sort(result.mOrderedFaces, mFaceComparator);
            } catch (Exception e) {
                Log.d(TAG, "parserFacePackageXml exception:", e);
            } finally {
                try {
                    if (fis != null) {
                        fis.close();
                    }
                } catch (Exception e) {
                }
            }
            return result;
        }

        private final void beginDocument(XmlPullParser parser, String firstElementName)
                throws XmlPullParserException, IOException {

            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
                ;
            }

            if (type != XmlPullParser.START_TAG) {
                throw new XmlPullParserException("No start tag found");
            }

            if (!parser.getName().equals(firstElementName)) {
                throw new XmlPullParserException(
                        "Unexpected start tag: found " + parser.getName() + ", expected " + firstElementName);
            }
        }

        private String getAttributeValue(XmlPullParser parser, int index) {

            try {
                return parser.getAttributeValue(index);
            } catch (Exception e) {
                Log.d(TAG, "getAttributeValue exception : " + e.getMessage());
            }
            return null;
        }

        private final Comparator<Face> mFaceComparator = new Comparator<Face>() {
            @Override
            public int compare(Face lhs, Face rhs) {
                
                return AppUtils.compare(lhs.mOrder, rhs.mOrder);
            }
        };
    }
    
    /**
     * 转换表情格式
     * 
     * @param content
     * @param isServer
     *            标识是否是上传到服务器中的表情 code
     * @return
     */
    public String replaceFaceFormat(String content, boolean isServer) {
        
        if (TextUtils.isEmpty(content)) {
            Log.w(TAG, "content is empty");
            return content;
        }
        
        Log.d(TAG, "replaceFaceFormat: before " + content);
        
        HashMap<String, String> faceFomat = new HashMap<String, String>();
        Matcher matcher = mFacePattern.matcher(content);
        
        while (matcher.find()) {
            
            String face = matcher.group();
            face = face.substring(1, face.length() - 1);
            String[] codes = face.split(":");
            face = "\\[" + face + "\\]";
            
            Log.d(TAG, "replaceFaceFormat: face " + face);
            
            if (faceFomat.containsKey(face)) {
                continue;
            }
            
            String faceKey = null;
            String faceCode = null;
            
            if (codes.length < FACE_CODES_LOWER_LIMIT) {
                continue;
            }
            
            faceKey = codes[0];
            faceCode = codes[1];
            
            if (TextUtils.isEmpty(faceKey) || TextUtils.isEmpty(faceCode)) {
                continue;
            }
            
            String replaceFace = "";
            
            if (isServer) {
                replaceFace = "[" + faceKey + faceCode + "]";
            } else {
                replaceFace = ConstantsUtil.SMILEY_LOCAL_ADDR.replace(ConstantsUtil.FACE_KEY, faceKey);
                replaceFace = replaceFace.replace(ConstantsUtil.FACE_CODE, faceCode);
            }
            
            replaceFace = replaceFace.replace(ConstantsUtil.FACE_CODE, faceCode);
            
            faceFomat.put(face, replaceFace);
        }
        
        Set<Map.Entry<String, String>> entryseSet = faceFomat.entrySet();
        for (Map.Entry<String, String> entry : entryseSet) {
            try {
                content = content.replaceAll(entry.getKey(), entry.getValue());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        Log.d(TAG, "replaceFaceFormat: after " + content);
        
        return content;
    }
}
